package main

import (
	"bufio"
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"github.com/schollz/progressbar/v3"
	"log"
	"os"
)

var (
	DB1 *gorm.DB
	DB2 *gorm.DB
)

type TableColumn struct {
	Field   string `gorm:"column:Field" json:"Field"`
	Type    string `gorm:"column:Type" json:"Type"`
	Null    string `gorm:"column:Null" json:"Null"`
	Key     string `gorm:"column:Key" json:"Key"`
	Default string `gorm:"column:Default" json:"Default"`
	Extra   string `gorm:"column:Extra" json:"Extra"`
}

var (
	greenBg      = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	whiteBg      = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellowBg     = string([]byte{27, 91, 57, 48, 59, 52, 51, 109})
	redBg        = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blueBg       = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magentaBg    = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyanBg       = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	green        = string([]byte{27, 91, 51, 50, 109})
	white        = string([]byte{27, 91, 51, 55, 109})
	yellow       = string([]byte{27, 91, 51, 51, 109})
	red          = string([]byte{27, 91, 51, 49, 109})
	blue         = string([]byte{27, 91, 51, 52, 109})
	magenta      = string([]byte{27, 91, 51, 53, 109})
	cyan         = string([]byte{27, 91, 51, 54, 109})
	reset        = string([]byte{27, 91, 48, 109})
	disableColor = false
)

func main() {
	log.Printf("欢迎使用！")
	log.Printf("比较数据表结构是否一致 \n")
	log.Printf("MYSQL1连接配置示例：user:pwd@(host:port)/db_name?charset=utf8&parseTime=True&loc=Local")
	log.Printf("MYSQL2连接配置示例：user:pwd@(host:port)/dbname?charset=utf8&parseTime=True&loc=Local")
	log.Printf("连接MYSQL配置1:\n")
	input := bufio.NewScanner(os.Stdin)
loop:
	input.Scan()
	mysqlOpenInfo := input.Text()
	if mysqlOpenInfo == "" {
		log.Println("请输入连接MYSQL配置1")
		goto loop
	}
	if db, err := conDb(mysqlOpenInfo); err != nil {
		log.Println("MySQL1启动异常", err)
		goto loop
	} else {
		DB1 = db
	}
	log.Printf("mysql")
	log.Printf("连接MYSQL配置2:\n")
loop2:
	input.Scan()
	mysqlOpenInfo2 := input.Text()
	if mysqlOpenInfo2 == "" {
		log.Println("请输入连接MYSQL配置2")
		goto loop
	}
	if db2, err := conDb(mysqlOpenInfo2); err != nil {
		log.Println("MySQL2启动异常", err)
		goto loop2
	} else {
		DB2 = db2
	}
	compare()
	//fmt.Println(fmt.Sprint("err1:", "d", "的"))

	defer func() {
		DB1.DB().Close()
		DB2.DB().Close()
	}()
}

func conDb(mysqlOpenInfo string) (*gorm.DB, error) {
	if db, err := gorm.Open("mysql", mysqlOpenInfo); err != nil {
		return nil, err
	} else {
		db.DB().SetMaxIdleConns(1)
		db.DB().SetMaxOpenConns(1)
		db.LogMode(false)
		return db, nil
	}
}

func compare() {
	var tables []string
	if rows, err := DB1.NewScope(nil).SQLDB().Query("SHOW TABLES"); err == nil {
		defer rows.Close()
		for rows.Next() {
			var table string
			rows.Scan(&table)
			tables = append(tables, table)
		}
	}
	bar := progressbar.Default(int64(len(tables)))
	var errStr []string
	for _, tableName := range tables {
		err := compareTable(tableName)
		if err != "" {
			errStr = append(errStr, err)
		}
		bar.Add(1)
	}
	log.Printf("对比结果如下:")
	if len(errStr) == 0 {
		log.Printf(green, "对比结果一致", reset)
	} else {
		for _, eInfo := range errStr {
			fmt.Println(red, eInfo, reset)
		}
	}
}

func compareTable(tableName string) string {
	var table1 []TableColumn
	var table2 []TableColumn
	sql := fmt.Sprintf("show columns from %s", tableName)
	err1 := DB1.Raw(sql).Scan(&table1).Error
	err2 := DB2.Raw(sql).Scan(&table2).Error
	if err1 != nil {
		return fmt.Sprint("err1:", err1)
	} else if err2 != nil {
		return fmt.Sprint("err2:", err2)
	} else {
		if len(table1) != len(table2) {
			return fmt.Sprint(tableName, "表字段数量不一致!")
		} else {
			fieldStr1 := ""
			fieldStr2 := ""
			for _, row := range table1 {
				fieldStr1 += row.Field
			}
			for _, row1 := range table2 {
				fieldStr2 += row1.Field
			}
			if fieldStr1 != fieldStr2 {
				return fmt.Sprint(tableName, "表字段顺序不一致!")
			}
		}
	}
	return ""
}
